/*******************************************************************************
 * Copyright (c) 2010 Mikhail Garber.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser Public License (LGPL)
 * which accompanies this distribution
 * 
 * Contributors:
 *     Mikhail Garber - initial API and implementation
 ******************************************************************************/
package plumber.process;

import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import plumber.common.HasSetup;

/**
 * 
 * default implementation of Flow Terminator - there is a single thread walking list of
 * running tasks and terminating them if they take too long
 *
 */
public class DefaultFlowTerminator implements FlowTerminator, HasSetup {

	protected static final long KILLER_DELAY = 3L * 1000L;
	private List<FlowTask> list = new ArrayList<FlowTask>();
	private Thread t = null;
	private Logger logger = LoggerFactory.getLogger(this.getClass());
	
	/* (non-Javadoc)
	 * @see plumber.process.FlowTerminator#register(plumber.process.FlowTask)
	 */
	@Override
	public void register(FlowTask task) {
		synchronized (list) {
			list.add(task);
		}
		logger.info("registered:" + task);
	}

	
	/**
	 * terminator logic - walk list of FlowTasks, check of their execution time exceeded 
	 * the time specified in Step configuration and then interrupt the task
	 * @see plumber.common.HasSetup#setup()
	 */
	@Override
	public void setup() {
		t = new Thread() {

			@Override
			public void run() {
				while(true) {
					try {
						List<FlowTask> copy = null;
						synchronized (list) {
							copy = new ArrayList<FlowTask>(list);
						}
						for(FlowTask task : copy) {
							if(!task.isDone()) {
								logger.info("checking task:" + task);
								long elapsed = System.currentTimeMillis() - task.getStarted().getTime();
								if(elapsed/1000L > task.getMaxSeconds()) {
									task.cancel(true);
								}
							}
						}
						Thread.sleep(KILLER_DELAY);
					} catch(InterruptedException ie) {
					  logger.warn("was interrupted");
					  return;
					} catch(Exception ex) {
						logger.warn("", ex);
					}
				}
			}
			
		};
		t.setDaemon(true);
		t.start();
		logger.info("started");
	}

	/* (non-Javadoc)
	 * @see plumber.common.HasSetup#shutdown()
	 */
	@Override
	public void shutdown() {
		if(t != null) {
			t.interrupt();
		}
		for(FlowTask task : list) {
			task.cancel(true);
		}
	}
	
	

}
